/* Copyright (c) 2009, Michael Patraw
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * The name of Michael Patraw may not be used to endorse or promote
 *       products derived from this software without specific prior written
 *       permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Michael Patraw ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Michael Patraw BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include <at/container/stack.h>

#include <assert.h>
#include <math.h>
#include <stdlib.h>

/******************************************************************************\
\******************************************************************************/

struct atStack_T
{
    atint top;
    atuint alloc;
    void **data;
};

/******************************************************************************\
\******************************************************************************/

atStack_T *atStack_Malloc(void)
{
    atStack_T *s = (atStack_T *)malloc(sizeof(atStack_T));
    
    if (!s)
        return NULL;
    
    s->data = (void **)malloc(sizeof(void *) * (atint)pow(2, 0));
    
    s->top = -1;
    s->alloc = 0;
    
    return s;
}



void atStack_Free(atStack_T *s)
{
    free(s->data);
    free(s);
}



void *atStack_Pop(atStack_T *s)
{
    void *d = s->data[s->top--];    
    
    if (atStack_Size(s) < (atint)pow(2, s->alloc - 1)) {
        if (s->alloc != 0) {
            s->alloc--;
            s->data = (void **)realloc(s->data, sizeof(void *) *
                                       (atint)pow(2, s->alloc));
            assert(s->data || !"Failed to allocated memory");
        }
    }
    
    return d;
}



void atStack_Push(atStack_T *s, void *d)
{
    if (atStack_Size(s) >= (atint)pow(2, s->alloc)) {
        s->alloc++;
        s->data = (void **)realloc(s->data, sizeof(void *) *
                                   (atint)pow(2, s->alloc));
        assert(s->data || !"Failed to allocated memory");
    }
    
    s->data[++s->top] = d;
}



atuint atStack_Size(atStack_T *s)
{
    return s->top + 1;
}



atint atStack_Find(atStack_T *s, void *d, Container_CmpF cmp)
{
    atuint i;
    
    for (i = 0; i < atStack_Size(s); ++i)
        if (cmp(d, s->data[i]) == 0)
            return i;
    
    return -1;
}

